package com.gigi.service.manual;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.Response;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gigi.entity.AskForLeaveEntity;
import com.gigi.entity.SignInEntity;
import com.gigi.entity.SignInRecordEntity;
import com.gigi.enums.ErrorCodeEnum;
import com.gigi.enums.SignInRecordStateEnum;
import com.gigi.enums.SignInTypeEnum;
import com.gigi.enums.YesOrNoEnum;
import com.gigi.mapper.manual.SignInManualMapper;
import com.gigi.mapper.manual.SignInRecordManualMapper;
import com.gigi.model.*;
import com.gigi.service.generated.AskForLeaveService;
import com.gigi.service.generated.SignInRecordService;
import com.gigi.service.generated.SignInService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class SignInRecordManageService {

    private final SignInRecordService signInRecordService;
    private final SignInService signInService;
    private final SignInRecordManualMapper signInRecordManualMapper;
    private final SignInManualMapper signInManualMapper;
    private final SignInManageService signInManageService;
    private final AskForLeaveService askForLeaveService;

    public SignInRecordManageService(SignInRecordService signInRecordService, SignInService signInService,
                                     SignInRecordManualMapper signInRecordManualMapper, SignInManualMapper signInManualMapper,
                                     SignInManageService signInManageService, AskForLeaveService askForLeaveService) {
        this.signInRecordService = signInRecordService;
        this.signInService = signInService;
        this.signInRecordManualMapper = signInRecordManualMapper;
        this.signInManualMapper = signInManualMapper;
        this.signInManageService = signInManageService;
        this.askForLeaveService = askForLeaveService;
    }

    /**
     * 签到成功/请假通过/补签通过后修改考勤记录为正常接口
     *
     * @param request
     * @return
     */
    public Response edit(SignInRecordDO request) {

        // 签到已过期，不能签到
        SignInEntity signInEntity = signInService.getById(request.getSignInId());
        if (YesOrNoEnum.YES.getCode().equals(signInEntity.getState())) {
            return Response.buildFailure(ErrorCodeEnum.OVERDUE.getErrCode(), ErrorCodeEnum.OVERDUE.getErrDesc());
        }

        // 已发起过请假申请，不能签到
        LambdaQueryWrapper<AskForLeaveEntity> askForLeaveWrapper = new LambdaQueryWrapper<AskForLeaveEntity>()
                .eq(AskForLeaveEntity::getSignInId, request.getSignInId())
                .eq(AskForLeaveEntity::getUserId, request.getUserId());
        if (askForLeaveService.count(askForLeaveWrapper) > 0) {
            return Response.buildFailure(ErrorCodeEnum.CAN_NOT_SIGN.getErrCode(), ErrorCodeEnum.CAN_NOT_SIGN.getErrDesc());
        }

        // 查发布签到时，初始化的缺勤记录
        LambdaQueryWrapper<SignInRecordEntity> wrapper = new LambdaQueryWrapper<SignInRecordEntity>()
                .eq(SignInRecordEntity::getSignInId, request.getSignInId())
                .eq(SignInRecordEntity::getUserId, request.getUserId());
        SignInRecordEntity oldModel = signInRecordService.getOne(wrapper, false);

        // 如果没有返回失败
        if (Objects.isNull(oldModel)) {
            return Response.buildFailure(ErrorCodeEnum.NO_DATA.getErrCode(), ErrorCodeEnum.NO_DATA.getErrDesc());
        }

        // 已经签到成功，不能重复签到
        if (SignInRecordStateEnum.SHOW.getCode().equals(oldModel.getState())) {
            return Response.buildFailure(ErrorCodeEnum.NO_NEED_SIGN.getErrCode(), ErrorCodeEnum.NO_NEED_SIGN.getErrDesc());
        }

        // 更新考勤状态为正常
        if (!editRecordToShow(oldModel.getId(), request.getPic())) {
            return Response.buildFailure(ErrorCodeEnum.EDIT_FAILED.getErrCode(), ErrorCodeEnum.EDIT_FAILED.getErrDesc());
        }

        return Response.buildSuccess();
    }

    private boolean editRecordToShow(Long id, String pic) {
        SignInRecordEntity entity = new SignInRecordEntity();
        entity.setId(id);
        entity.setState(SignInRecordStateEnum.SHOW.getCode());
        entity.setSignInTime(LocalDateTime.now());
        entity.setPic(pic);
        return signInRecordService.updateById(entity);
    }

    /**
     * 教师端考勤统计接口
     *
     * @param request
     * @return
     */
    public MultiResponse<SignInRecordDO> statistics(IdRequest request) {
        List<SignInRecordDO> signInRecordDOS = signInRecordManualMapper.listSignInRecord(request.getId());
        if (CollUtil.isNotEmpty(signInRecordDOS)) {
            signInRecordDOS.forEach(e -> {
                e.setSignInTimeStr(DateUtil.format(e.getSignInTime(), DatePattern.NORM_DATETIME_PATTERN));
            });
        }
        return MultiResponse.ofWithoutTotal(signInRecordDOS);
    }

    /**
     * 学生端考勤统计接口
     *
     * @param request
     * @return
     */
    public SingleResponse<StudentStatisticsDO> count(CountSignInRecordRequest request) {
        StudentStatisticsDO statisticsDO = new StudentStatisticsDO();
        List<SignInRecordDO> signInRecordDOS = signInRecordManualMapper.countSignInRecord(request.getCourseId(), request.getUserId());
        if (CollUtil.isEmpty(signInRecordDOS)) {
            return SingleResponse.of(statisticsDO);
        }
        Map<Integer, List<SignInRecordDO>> map = signInRecordDOS.stream().collect(Collectors.groupingBy(SignInRecordDO::getState));
        statisticsDO.setShowCount(Objects.nonNull(map.get(0)) ? map.get(0).size() : 0);
        statisticsDO.setUnShowCount(Objects.nonNull(map.get(1)) ? map.get(1).size() : 0);
        statisticsDO.setExtraCount(Objects.nonNull(map.get(2)) ? map.get(2).size() : 0);
        statisticsDO.setAskForLeaveCount(Objects.nonNull(map.get(3)) ? map.get(3).size() : 0);
        return SingleResponse.of(statisticsDO);
    }

    /**
     * 导出考勤统计excel接口
     *
     * @param request
     * @return
     */
    public Response excel(IdRequest request) {
        // 准备数据

        // 签到基本信息
        SignInDO signInInfo = signInManualMapper.getSignInInfo(request.getId());
        if (Objects.isNull(signInInfo)) {
            return SingleResponse.buildFailure(ErrorCodeEnum.NO_DATA.getErrCode(), ErrorCodeEnum.NO_DATA.getErrDesc());
        }
        signInInfo.setTypeDesc(SignInTypeEnum.getEnumByCode(signInInfo.getType()).getDesc());
        signInInfo.setClassName(signInManageService.getClassName(signInInfo.getClassesIdStr()));
        signInInfo.setStartTimeStr(DateUtil.format(signInInfo.getStartTime(), DatePattern.NORM_DATETIME_PATTERN));
        signInInfo.setEndTimeStr(DateUtil.format(signInInfo.getEndTime(), DatePattern.NORM_DATETIME_PATTERN));

        // 签到考勤列表
        List<SignInRecordDO> signInRecordDOS = signInRecordManualMapper.listSignInRecord(request.getId());
        if (CollUtil.isNotEmpty(signInRecordDOS)) {
            signInRecordDOS.forEach(e -> {
                e.setSignInTimeStr(DateUtil.format(e.getSignInTime(), DatePattern.NORM_DATETIME_PATTERN));
                e.setStateDesc(SignInRecordStateEnum.getEnumByCode(e.getState()).getDesc());
            });
        }

        // 创建一个excel
        String fileName = "/Users/zhangyingying/Desktop/考勤统计.xlsx"; // 写想生成文件的路径

        // 向excel中写数据
        ExcelWriter excelWriter = EasyExcel.write(fileName).build();
        WriteSheet writeSheet = EasyExcel.writerSheet("考勤统计").needHead(Boolean.FALSE).build();
        WriteTable writeTable0 = EasyExcel.writerTable(0).head(SignInDO.class).needHead(Boolean.TRUE).build();
        WriteTable writeTable1 = EasyExcel.writerTable(1).head(SignInRecordDO.class).needHead(Boolean.TRUE).build();
        excelWriter.write(Collections.singletonList(signInInfo), writeSheet, writeTable0);
        excelWriter.write(signInRecordDOS, writeSheet, writeTable1);
        excelWriter.finish();

        return Response.buildSuccess();
    }


}
